namespace Trading.IBApi

open System 
open DateTimeExtensions
open com.ib.client

type BarSize =
    | Bar1Secs
    | Bar5Secs
    | Bar15Secs
    | Bar30Secs
    | Bar1Min
    | Bar2Mins
    | Bar3Mins
    | Bar5Mins
    | Bar15Mins
    | Bar30Mins
    | Bar1Hour
    | Bar4Hours
    | Bar1Day
    | Bar1Week
    | Bar1Month
    | Bar3Months
    | Bar1Year

    override self.ToString() = 
        let num, units = (sprintf "%A" self).Substring(3) |> Seq.toArray |> Array.partition Char.IsDigit 
        String(num) + " " + String(units).ToLower()

type Size = int
type PriceType = double
type Tick = 
    | AskPrice of PriceType  
    | BidPrice of PriceType
    | LastPrice of PriceType 
    | LastTimestamp of DateTime
    | AskSize of Size
    | BidSize of Size
    | Volume of Size   
    | LastSize of Size  
    | Unknown of string

    override this.ToString() = 
        match this with
        | LastPrice value -> sprintf "LastPrice=%f" value
        | LastSize value -> sprintf "LastSize=%d" value
        | AskSize value -> sprintf "AskSize=%d" value
        | BidSize value -> sprintf "BidSize=%d" value
        | Volume value -> sprintf "Volume=%d" value
        | LastTimestamp value -> sprintf "LastTimestamp=%O" value
        | AskPrice value -> sprintf "AskPrice=%f" value
        | BidPrice value -> sprintf "BidPrice=%f" value
        | Unknown tickType -> sprintf "Unknown tick type - %O" tickType

    static member Parse(input : string) =
        match input.ToLower().Split('=') with 
        | [| "lastprice"; value |] -> value |> double |> LastPrice 
        | [| "lastsize"; value |] -> value |> int |> LastSize 
        | [| "volume"; value |] -> value |> int |> Volume 
        | [| "lasttimestamp"; value |] -> value |> DateTime.FromUnixTime |> LastTimestamp 
        | [| "askprice"; value |] -> value |> double |> AskPrice 
        | [| "bidprice"; value |] -> value |> double |> BidPrice 
        | [| tickType; _ |] -> Unknown tickType
        | _ -> invalidArg "input" input

type ActionSide = Buy | Sell

type PriceBar = {
    Date: DateTime
    Open: double
    High: double
    Low: double
    Close: double
    Volume: int
    Count: int
    WAP: double
    HasGaps: bool
}

type RealTimeBar = {
    Date: DateTime
    Open: double
    High: double
    Low: double
    Close: double
    Volume: int
    Count: int
    WAP: double
}

type HistorySpanUnit = 
    | Seconds
    | Days
    | Weeks
    | Months
    | Years

    override this.ToString() = (sprintf "%A" this).Substring(0, 1)

type HistorySpan = int * HistorySpanUnit


type IBrokerGateway =

    abstract Errors : IObservable<string>
    abstract ConnectionInfo : string

    abstract Ticks : Contract -> IObservable<Tick>
    abstract ContractDetails : (ContractDetails -> 'T) -> Contract -> Async<'T array>

    abstract HistoricalData : Contract * till: DateTime * span: HistorySpan * barSize: BarSize * whatToShow: string * ?useRTH: int -> Async<PriceBar array>
    abstract RealTimeBars : Contract * whatToShow: string * ?useRTH: int -> IObservable<RealTimeBar>
    abstract PlaceOrder : Contract * Order -> Async<unit>
